/*
 * Copyright (C) 2005 David Orme <djo@coconut-palm-software.com>
 * 
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 * 
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     David Orme     - Initial API and implementation
 *     The Pampered Chef - Expanded to handle sorting
 */
package org.eclipse.nebula.widgets.compositetable;


import java.util.ArrayList;
import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;

/**
 * Class AbstractSortableHeader. A Header class making it easier to implement a
 * sorted table where clicking on a header column sets or changes the sort
 * order.
 * 
 * @author djo
 */
public abstract class AbstractSortableHeader extends Composite {

    protected List labels;
    private String[] labelStrings;

	private MouseAdapter sortMouseAdapter;
	private Boolean sortDescending = null; // choices: null (no sort); true; false

	private int lastSortColumn = -1;
	protected Image sortUpIndicator = new Image(Display.getDefault(), getUpImageData());
	protected Image sortDownIndicator = new Image(Display.getDefault(), getDownImageData());

	private Image sortIndicator = null;

	final int width = 8;
	final int height = 4;

	private ImageData getEmptyImageData() {
		final RGB whiteRGB = new RGB(255, 255, 255); // The transparancy color
		final RGB blackRGB = new RGB(0, 0, 0);

		PaletteData palette = new PaletteData(new RGB[] { whiteRGB, blackRGB });
		ImageData imageData = new ImageData(width, height, 1, palette);
		int whitePixel = imageData.palette.getPixel(whiteRGB);
		imageData.transparentPixel = whitePixel;
		return imageData;
	}

	private ImageData getUpImageData() {
		ImageData imageData = getEmptyImageData();
		int numTransparentPixels = 0;
		for (int row = height - 1; row >= 0; --row) {
			for (int col = numTransparentPixels; col < width / 2; ++col) {
				imageData.setPixel(col, row, 1);
				imageData.setPixel(width - col - 1, row, 1);
			}
			++numTransparentPixels;
		}
		return imageData;
	}

	private ImageData getDownImageData() {
		ImageData imageData = getEmptyImageData();
		int numTransparentPixels = 0;
		for (int row = 0; row < height; ++row) {
			for (int col = numTransparentPixels; col < width / 2; ++col) {
				imageData.setPixel(col, row, 1);
				imageData.setPixel(width - col - 1, row, 1);
			}
			++numTransparentPixels;
		}
		return imageData;
	}

	/**
     * 
	 * @param parent
	 * @param style
	 */
	public AbstractSortableHeader(Composite parent, int style) {
		super(parent, style);
		makeMouseAdapter();
		addDisposeListener(new DisposeListener() {
			public void widgetDisposed(DisposeEvent arg0) {
				sortUpIndicator.dispose();
				sortDownIndicator.dispose();
			}
		});
	}

	private boolean toggleSortDirection() {
		if (sortDescending == null) {
			sortDescending = Boolean.TRUE;
			sortIndicator = sortDownIndicator;
			return sortDescending.booleanValue();
		}
		sortDescending = new Boolean(!sortDescending.booleanValue());
		if (sortDescending.booleanValue()) {
			sortIndicator = sortDownIndicator;
		} else {
			sortIndicator = sortUpIndicator;
		}
		return sortDescending.booleanValue();
	}

	private void makeMouseAdapter() {
		this.sortMouseAdapter = new MouseAdapter() {

			public void mouseDown(MouseEvent e) {
				CLabel label = (CLabel) e.widget;
				int c = labels.indexOf(label);
				if (c != lastSortColumn) {
					sortDescending = null;
					sortIndicator = null;
				}
				lastSortColumn = c;
				sortOnColumn(c, toggleSortDirection());

				for (int i = 0; i < labels.size(); i++) {
					CLabel labelToSet = (CLabel) labels.get(i);
					if (i != c) {
						labelToSet.setImage(null);
					} else {
						labelToSet.setImage(sortIndicator);
					}
				}
			}
		};
	}

	/**
	 * Clients must override this method to reset the current sort column.
	 * 
	 * @param column
	 *            The column on which to sort
	 * @param sortDescending
	 *            true if the sort should be in descending order; false for
	 *            ascending order
	 */
	protected abstract void sortOnColumn(int column, boolean sortDescending);

    /**
     * Clients must call this method (normally in the constructor) to set the
     * column names.
     * 
     * @param columnText String[] The text to display in each column
     */
    public void setColumnText(String[] columnText) {
        this.labelStrings = columnText;
        initialize();
    }

    private void initialize() {
        this.labels = new ArrayList();
        String[] fields = labelStrings;
        for (int i = 0; i < fields.length; i++) {
            CLabel label = new CLabel(this, SWT.NONE);
            if (label.isDisposed()) return;
            this.labels.add(label);
            label.setText(fields[i]);
            initializeLabel(label);
        }
    }
    
    protected void initializeLabel(CLabel label) {
        label.addMouseListener(this.sortMouseAdapter);
    }
}
